using System;
using System.Collections.Generic;
using System.Text;

namespace TidhiGanitam.DataModel
{
    [Serializable]
    public class Rasi
    {
        private double dDegrees;

        #region properties
        public double RawValue
        {
            get { return dDegrees; }
            set
            { dDegrees = value; }
        }
        public double Rasulu
        {
            get
            {
                double dRasi = MathHelper.GetDegrees(dDegrees);
                int iRasi = (int) dRasi / 30;
                iRasi = iRasi % 12;
                return Convert.ToDouble(iRasi);

            }
        }
        public double Bhagalu
        {
            get
            {
                double dBhaga = MathHelper.GetDegrees(dDegrees);
                return dBhaga % 30;
            }
        }
        public double Liptalu
        {
            get
            {
                return MathHelper.GetMinutes(dDegrees);
            }
        }

        public double Viliptalu
        {
            get
            {
                return MathHelper.GetSeconds(dDegrees);
            }
        }
        public double Paralu
        {
            get
            {
                return MathHelper.GetMilliSeconds(dDegrees);
            }
        }
        public override string ToString()
        {
            string sRetString = string.Empty;
            sRetString = string.Format("{4}{0}-{1}-{2}-{3}", Rasulu.ToString(),
                                            Bhagalu.ToString(),
                                            Liptalu.ToString(),
                                            Viliptalu.ToString(),
                                            ((dDegrees >= 0) ? "" : "-"));

            return sRetString;
        }
        public string DisplayFormat(Enums.DisplayFormat Format)
        {
            string sRetString = string.Empty;
            switch (Format)
            {
                case Enums.DisplayFormat.Default:
                    sRetString = this.ToString();
                    break;
                case Enums.DisplayFormat.BLV:
                    sRetString = string.Format("{3}{0}-{1}-{2}", ((double)((Rasulu * 30) + Bhagalu)).ToString(),
                                                    Liptalu.ToString(),
                                                    Viliptalu.ToString(),
                                                    ((dDegrees >= 0) ? "" : "-"));
                    break;
                case Enums.DisplayFormat.LV:
                    sRetString = string.Format("{2}{0}-{1}", ((double)((Rasulu * 30) + Bhagalu) * 60 + Liptalu).ToString(),
                                Viliptalu.ToString(),
                                ((dDegrees >= 0) ? "" : "-"));
                    break;
                case Enums.DisplayFormat.RBLVP:
                    sRetString = string.Format("{5}{0}-{1}-{2}-{3}-{4}", Rasulu.ToString(),
                                                    Bhagalu.ToString(),
                                                    Liptalu.ToString(),
                                                    Viliptalu.ToString(),
                                                    Paralu.ToString(),
                                                    ((dDegrees >= 0) ? "" : "-"));
                    break;
                case Enums.DisplayFormat.BLVP:
                    sRetString = string.Format("{4}{0}-{1}-{2}-{3}", ((double)((Rasulu * 30) + Bhagalu)).ToString(),
                                                    Liptalu.ToString(),
                                                    Viliptalu.ToString(),
                                                    Paralu.ToString(),
                                                    ((dDegrees >= 0) ? "" : "-"));
                    break;
                case Enums.DisplayFormat.LVP:
                    sRetString = string.Format("{3}{0}-{1}-{2}", ((double)((Rasulu * 30) + Bhagalu) * 60 + Liptalu).ToString(),
                                                    Viliptalu.ToString(),
                                                    Paralu.ToString(),
                                                    ((dDegrees >= 0) ? "" : "-"));
                    break;
                case Enums.DisplayFormat.HMS12:
                    double TempLiptalu = (double)((Rasulu * 30) + Bhagalu) * 60 + Liptalu;
                    TempLiptalu = TempLiptalu % 12;
                    if (TempLiptalu == 0)
                    {
                        TempLiptalu = 12;
                    }
                    sRetString = string.Format("{0}-{1}", TempLiptalu.ToString(),
                                Viliptalu.ToString()); 
                    break;
            }
            return sRetString;
         }

        #endregion

        public Rasi()
        {
            dDegrees = 0d;
        }
        public Rasi(Rasi rasi)
            :this()
        {
            dDegrees = rasi.dDegrees;
        }
        public Rasi(double rasulu, double bhagalu, double liptalu,
                double viliptalu, double paralu)
        {
            dDegrees = GetRasiValue(rasulu, bhagalu, liptalu, viliptalu, paralu);
        }
        public Rasi(double rasulu, double bhagalu, double liptalu,
                double viliptalu)
        {
            dDegrees = GetRasiValue(rasulu, bhagalu, liptalu, viliptalu,0);
        }
        public Rasi(double rasulu, double bhagalu, double liptalu)
        {
            dDegrees = GetRasiValue(rasulu, bhagalu, liptalu, 0, 0);
        }

        public Rasi(double rasulu, double bhagalu)
        {
            dDegrees = GetRasiValue(rasulu, bhagalu, 0, 0, 0);
        }
        public Rasi(double bhagalu)
        {
            dDegrees = GetRasiValue(0, bhagalu, 0, 0, 0);
        }
        private double GetRasiValue(double rasulu, double bhagalu, double liptalu,
            double viliptalu, double paralu)
        {
            int iMultiplier = 1;
            if (rasulu < 0 || bhagalu < 0 || liptalu < 0 || viliptalu < 0 || paralu < 0)
            {
                iMultiplier = -1;
                rasulu = Math.Abs(rasulu); bhagalu = Math.Abs(bhagalu); liptalu = Math.Abs(liptalu);
                viliptalu = Math.Abs(viliptalu); paralu = Math.Abs(paralu);
            }
            double ddegrees = iMultiplier * (rasulu * 30 + bhagalu + liptalu / 60 + viliptalu / 3600 + paralu / 216000);
            return ddegrees;
        }
        #region operator overloading routines

        public static Rasi operator +(Rasi op1, Rasi op2)
        {
            Rasi RetVal = new Rasi();
            RetVal.dDegrees = op1.dDegrees + op2.dDegrees;
            return RetVal;
        }
        public static Rasi operator +(Rasi op1, double op2)
        {
            Rasi RetVal = new Rasi();
            RetVal.dDegrees = op1.dDegrees + op2;
//            RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator -(Rasi op1, Rasi op2)
        {
            Rasi Operand1 = new Rasi(op1);
            Rasi Operand2 = new Rasi(op2);
            Rasi RetVal = new Rasi();
            if (Operand1 < Operand2)
            {
                Operand1.dDegrees += 360d;
            }
            RetVal.dDegrees = Operand1.dDegrees - Operand2.dDegrees;
            //RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator -(Rasi op1, double op2)
        {
            Rasi Operand1 = new Rasi(op1);
            Rasi RetVal = new Rasi();
            if (Operand1.dDegrees < op2)
            {
                Operand1 += 12d;
            }
            RetVal.dDegrees = Operand1.dDegrees - op2;
            //RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator *(Rasi op1, Rasi op2)
        {
            Rasi RetVal = new Rasi();
            RetVal.dDegrees = op1.dDegrees * op2.dDegrees;
            //RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator *(Rasi op1, double op2)
        {
            Rasi RetVal = new Rasi();
            RetVal.dDegrees = op1.dDegrees * op2;
            //RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator /(Rasi op1, Rasi op2)
        {
            Rasi RetVal = new Rasi();
            if (op2.dDegrees != 0)
            {
                RetVal.dDegrees = op1.dDegrees / op2.dDegrees;
            }
            //RetVal.Refresh();
            return RetVal;
        }
        public static Rasi operator /(Rasi op1, double op2)
        {
            Rasi RetVal = new Rasi();
            if (op2 != 0)
            {
                RetVal.dDegrees = op1.dDegrees / op2;
            }
            //RetVal.Refresh();
            return RetVal;
        }
        public static bool operator >(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees > op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool operator >=(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees >= op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool operator ==(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees == op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool operator <(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees < op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool operator <=(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees < op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public static bool operator !=(Rasi op1, Rasi op2)
        {
            bool ReturnValue = false;
            if (op1.dDegrees != op2.dDegrees)
            {
                ReturnValue = true;
            }
            return ReturnValue;
        }
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

#endregion

        public void Refresh()
        {
            this.dDegrees = dDegrees % 360;
        }
        public Rasi Round()
        {
           Refresh();
           double iMultiplier = this.dDegrees >= 0 ? 1 : -1;
           Rasi RetVal = new Rasi(this.Rasulu, this.Bhagalu,this.Liptalu, this.Viliptalu);
           return RetVal * iMultiplier;
        }
        public static Rasi AbsoluteDifference(Rasi op1, Rasi op2)
        {
            double dDiff = Math.Abs(op1.dDegrees - op2.dDegrees);
            return new Rasi(dDiff);
        }
        public static Rasi Difference(Rasi op1, Rasi op2)
        {
            return new Rasi(op1.dDegrees - op2.dDegrees);
        }
        /// <summary>
        /// This method returns Time of the day of the Rasi. Suryodayamu Samskaramu is done here
        /// </summary>
        /// <param name="SuryoDayamu"></param>
        /// <returns></returns>
        public string GetTimeFormatString(Rasi Suryodayamu, bool withTimePrefix)
        {
            string sRetString = string.Empty;
            Rasi TimeConversion = new Rasi(dDegrees * 0.4) + Suryodayamu;
            string TimePrefix = Constants.GetTimePrefix(TimeConversion);
            if (TimeConversion > new Rasi(0, 0, 24, 0))
            {
                TimeConversion = new Rasi(TimeConversion - new Rasi(0, 0, 24, 0));
            }
            else if (TimeConversion > new Rasi(0, 0, 12, 0))
            {
                TimeConversion = new Rasi(TimeConversion - new Rasi(0, 0, 12, 0));
            }
            if (TimeConversion.Liptalu == 0)
            {
                TimeConversion += new Rasi(0, 0, 12, 0);
            }
            string TimeString = TimeConversion.DisplayFormat(Enums.DisplayFormat.LV);
            if (withTimePrefix)
            {
                sRetString = string.Format("{0}. {1}", TimePrefix, TimeString);
            }
            else
            {
                sRetString = string.Format("{0}", TimeString);
            }
            return sRetString;
        }
    }
}
